package com.guguskins.back.utils;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class JwtUtil {

    /**
     * token 过期时间, 单位: 秒. 这个值表示 30 天
     */
    private static final long TOKEN_EXPIRED_TIME = 30 * 24 * 60 * 60 * 1000L;

//    public static final String jwtId = "tokenId";

    /**
     * jwt 加密解密密钥(可自行填写)
     */
    private static final String JWT_SECRET = "guguskins";

    /**
     * 创建JWT
     */
    public static String createToken(String jwtId, Map<String, Object> claims, Long time) {
        SecretKey secretKey = generalKey();
        //下面就是在为payload添加各种标准声明和私有声明了
        //这里其实就是new一个JwtBuilder，设置jwt的body
        JwtBuilder builder = Jwts.builder()
                //设置jti(JWT ID)：是JWT的唯一标识，根据业务需要，这个可以设置为一个不重复的值，主要用来作为一次性token,从而回避重放攻击。
                .setId(jwtId)
                //如果有私有声明，一定要先设置这个自己创建的私有的声明，这个是给builder的claim赋值，一旦写在标准的声明赋值之后，就是覆盖了那些标准的声明的
                .setClaims(claims)
                //iat: jwt的签发时间
                .setIssuedAt(new Date())
                //指定签名的时候使用的签名算法，也就是header那部分，jjwt已经将这部分内容封装好了。
                //设置签名使用的签名算法和签名使用的秘钥
                .signWith(SignatureAlgorithm.HS256, secretKey)
                //设置过期时间
                .setExpiration(new Date(System.currentTimeMillis() + TOKEN_EXPIRED_TIME));
        return builder.compact();
    }

    /**
     * 验证jwt
     */
    public static Claims verifyToken(String token) {
        //签名秘钥，和生成的签名的秘钥一模一样
        SecretKey key = generalKey();
        //得到DefaultJwtParser
        return Jwts.parser()
                //设置签名的秘钥
                .setSigningKey(key)
                .parseClaimsJws(token)
                .getBody();
    }

    /**
     * 由字符串生成加密key
     *
     * @return
     */
    public static SecretKey generalKey() {
        String stringKey = JWT_SECRET;
//        byte[] encodedKey = Base64.decodeBase64(stringKey);
        return new SecretKeySpec(stringKey.getBytes(StandardCharsets.UTF_8), 0, stringKey.length(), "AES");
    }

    /**
     * 根据userId和openid生成token
     */
    public static String generateToken(Long id) {
        Map<String, Object> map = new HashMap<>();
        map.put("userId", id);
        return createToken(id.toString(), map, TOKEN_EXPIRED_TIME);
    }

    public static void main(String[] args) {

        Claims token = verifyToken("eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyTmFtZSI6ImFkbWluIiwicGVybWlzc2lvbkxpc3QiOlsiIl19.gGPB-ZRGgxkTqOY5_3AcIG0uc3IIMnKKOUu9_wKiNLo");
        Long userId = token.get("userId", Long.class);
        System.err.println(userId);
//         生成token
//        String s = generateToken("admin", "123456");
//        System.out.println(s);

//         验证
//        String token = "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMTEiLCJvcGVuSWQiOiIxMTEiLCJleHAiOjE1OTI1NTc3ODMsInVzZXJJZCI6MjAsImlhdCI6MTU5MjU1NTE5MSwianRpIjoidG9rZW5JZCJ9.X7JHnx3Y5wtb-n3pT9tft2I4hENJdeRxW2QWaI4jv2E";
//        Claims claims = verifyToken(token);
//        String subject = claims.getSubject();
//        String userId = (String) claims.get("userId");
//        String openId = (String) claims.get("openId");
//        String sub = (String) claims.get("sub");
//        System.out.println("subject:" + subject);
//        System.out.println("userId:" + userId);
//        System.out.println("openId:" + openId);
//        System.out.println("sub:" + sub);
    }
}